/**
 * 
 */
package ar.utn.frgp.banco.dao.impl;

import genericos.dao.exeptions.PersistanceException;
import genericos.dao.exeptions.PersistenceServiceException;

import java.math.BigDecimal;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;

import ar.utn.frgp.banco.dao.CuentasDAO;
import ar.utn.frgp.banco.dao.EBAbstractDAO;
import ar.utn.frgp.banco.entity.Cuenta;
import ar.utn.frgp.banco.entity.enums.OrigenMovimiento;
import ar.utn.frgp.banco.entity.enums.TipoCuenta;
import ar.utn.frgp.banco.exceptions.DataAccessException;
import ar.utn.frgp.banco.exceptions.PersonalisedException;

/**
 * @author PUSDERKIS
 *
 */
public class CuentasDAOImpl extends EBAbstractDAO implements CuentasDAO {

	/**
	 * @see ar.utn.frgp.banco.dao.CuentasDAO#updateSaldos(ar.utn.frgp.banco.entity.Cuenta)
	 */
	public void updateSaldos(Cuenta cuenta) throws DataAccessException {
		// TODO Auto-generated method stub

	}

	/**
	 * @see ar.utn.frgp.banco.dao.CuentasDAO#existeCuenta(ar.utn.frgp.banco.entity.Cuenta)
	 */
	public boolean existeCuenta(Cuenta cuenta) throws PersonalisedException {
		// TODO Auto-generated method stub
		return false;
	}

	/**
	 * @see ar.utn.frgp.banco.dao.CuentasDAO#existeCuenta(java.lang.Long)
	 */
	public boolean existeCuenta(Long idCuenta) throws PersonalisedException {
		// TODO Auto-generated method stub
		return false;
	}

	/**
	 * @see ar.utn.frgp.banco.dao.CuentasDAO#obtenerCuentas(java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	public List<Cuenta> obtenerCuentas(String dni) throws PersonalisedException {
		
		String sQuery="SELECT cta FROM Cliente c INNER JOIN c.cuentas cta WHERE c.dni = :dni";
		
		try {
			Query query = universalHibernateDAO.getHibernateSession().createQuery(sQuery);
			query.setString("dni", dni);
			
			return query.list();
		} catch (HibernateException e) {
			logger.error("Ocurrio un error al recuperar la lista de cuentas para el usuario: DNI"+dni,e);
			throw new DataAccessException("Error al recuperar la lista de cuentas para el usuario: DNI"+dni,e);
		} catch (PersistanceException e) {
			logger.error("Ocurrio un error al recuperar la lista de cuentas para el usuario: DNI"+dni,e);
			throw new DataAccessException("Error al recuperar la lista de cuentas para el usuario: DNI"+dni,e);
		}
	}

	/**
	 * @see ar.utn.frgp.banco.dao.CuentasDAO#obtenerCuenta(java.lang.Long)
	 */
	public Cuenta obtenerCuenta(Long nroCuenta) throws DataAccessException {
		
		String sQuery="FROM Cuenta c WHERE c.numero = :nroCuenta";
		
		try {
			Query query = universalHibernateDAO.getHibernateSession().createQuery(sQuery);
			
			query.setLong("nroCuenta", nroCuenta);
			
			return (Cuenta)query.uniqueResult();
		} catch (Exception e) {
			// TODO: handle exception
			return null;
		}
	}

	/**
	 * @see ar.utn.frgp.banco.dao.CuentasDAO#crearCuenta(ar.utn.frgp.banco.entity.Cuenta, java.lang.String)
	 */
	public Long crearCuenta(Cuenta cta, String dni)
			throws PersonalisedException {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * @see ar.utn.frgp.banco.dao.CuentasDAO#cantidadCuentas(java.lang.String, ar.utn.frgp.banco.entity.enums.TipoCuenta)
	 */
	public int cantidadCuentas(String dni, TipoCuenta tipo)
			throws PersonalisedException {
	
		String sQuery = "SELECT COUNT(c) FROM Cliente cl INNER JOIN cl.cuentas c where cl.dni = :dni AND c.tipoCuenta = :tipo";
		
		try {
			Query q = universalHibernateDAO.getHibernateSession().createQuery(sQuery);
			q.setString("dni", dni);
			q.setParameter("tipo", tipo);
			
			Long cant = (Long) q.uniqueResult();
			
			return cant != null ? cant.intValue() : 0;
			
		} catch (PersistenceServiceException e) {
			logger.error("Ocurrio un error al contar las cuentas corrientes.",e);
			throw new DataAccessException("Ocurrio un error al contar las cuentas corrientes.",e);
		} catch (HibernateException e) {
			logger.error("Ocurrio un error al contar las cuentas corrientes.",e);
			throw new DataAccessException("Ocurrio un error al contar las cuentas corrientes.",e);
		} catch (PersistanceException e) {
			logger.error("Ocurrio un error al contar las cuentas corrientes.",e);
			throw new DataAccessException("Ocurrio un error al contar las cuentas corrientes.",e);
		}
	}

	/**
	 * @see ar.utn.frgp.banco.dao.CuentasDAO#extraccion(java.lang.Long, java.math.BigDecimal, ar.utn.frgp.banco.entity.enums.OrigenMovimiento)
	 */
	public void extraccion(Long idCuenta, BigDecimal monto,
			OrigenMovimiento origen) throws DataAccessException {
		// TODO Auto-generated method stub

	}

	/**
	 * @see ar.utn.frgp.banco.dao.CuentasDAO#deposito(java.lang.Long, java.math.BigDecimal, ar.utn.frgp.banco.entity.enums.OrigenMovimiento)
	 */
	public void deposito(Long idCuenta, BigDecimal monto,
			OrigenMovimiento origen) throws DataAccessException,
			PersonalisedException {
		// TODO Auto-generated method stub

	}

	/**
	 * @see ar.utn.frgp.banco.dao.CuentasDAO#transferencia(java.lang.Long, java.math.BigDecimal, java.lang.Long)
	 */
	public void transferencia(Long idCuentaOrigen, BigDecimal monto,
			Long idCuentaDestino) throws DataAccessException,
			PersonalisedException {
		// TODO Auto-generated method stub

	}

	public int cantidadCuentasCorrientes(String dni) throws DataAccessException {
		
		String sQuery = "SELECT COUNT(c) FROM Cliente cl INNER JOIN cl.cuentas c where cl.dni = :dni && c.tipo = :tipo";
		
		try {
			Query q = universalHibernateDAO.getHibernateSession().createQuery(sQuery);
			q.setString("dni", dni);
			
			Long cant = (Long) q.uniqueResult();
			
			return cant != null ? cant.intValue() : 0;
			
		} catch (PersistenceServiceException e) {
			logger.error("Ocurrio un error al contar las cuentas corrientes.",e);
			throw new DataAccessException("Ocurrio un error al contar las cuentas corrientes.",e);
		} catch (HibernateException e) {
			logger.error("Ocurrio un error al contar las cuentas corrientes.",e);
			throw new DataAccessException("Ocurrio un error al contar las cuentas corrientes.",e);
		} catch (PersistanceException e) {
			logger.error("Ocurrio un error al contar las cuentas corrientes.",e);
			throw new DataAccessException("Ocurrio un error al contar las cuentas corrientes.",e);
		}
		
	}

}
